package com.example.token;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
import org.apache.shiro.realm.Realm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Collection;

/**
 * 自定义认证器
 * ModularRealmAuthenticator 是 Shiro 默认的“多 Realm 认证执行器”
 * 但默认行为是链式处理（遍历所有 Realm 尝试认证），自定义逻辑实现了 分支处理：根据 loginType 调用对应 Realm
 * <p></p>
 * LoginController
 * ↓
 * MyToken(username, password, loginType)
 * ↓
 * MyModularRealmAuthenticator.doAuthenticate(token)
 * ↓
 * 从所有 Realm 中找出 loginType 开头的 Realm
 * ↓
 * ┌──────────────┐
 * │ userRealm()  │ ← loginType = "user"
 * └──────────────┘
 * ↓
 * doSingleRealmAuthentication(...)
 * ↓
 * 认证成功 / 失败
 */
public class MyModularRealmAuthenticator extends ModularRealmAuthenticator {

    Logger logger = LoggerFactory.getLogger(MyModularRealmAuthenticator.class);

    @Override
    protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {
        logger.info("MyModularRealmAuthenticator");
        /**
         * 校验 Shiro 已配置至少一个 Realm
         */
        this.assertRealmsConfigured();
        /**
         * 获取所有配置的 Realm
         * 强制类型转换为 MyToken，提取登录类型（如 "user"、"admin"）
         */
        Collection<Realm> realms = this.getRealms();
        MyToken myToken = (MyToken) authenticationToken;
        String loginType = myToken.getLoginType();
        logger.info("loginType:" + loginType);
        /**
         * 根据 loginType 匹配对应的 Realm
         * 要求你的 Realm 名称以 loginType 开头，如 "userRealm" 对应 "user"
         */
        Collection<Realm> typeRealms = new ArrayList<>();
        for (Realm realm : realms) {
            if (realm.getName().startsWith(loginType)) {
                typeRealms.add(realm);
            }
        }
        /**
         * 如果只找到一个匹配 Realm，就执行单 Realm 认证
         * 如果找到多个，就做多 Realm 链式认证（少见，但保留可能性）
         */
        if (typeRealms.size() == 1) {
            return this.doSingleRealmAuthentication((Realm) typeRealms.iterator().next(), authenticationToken);
        } else {
            return this.doMultiRealmAuthentication(typeRealms, authenticationToken);
        }
    }

}
